package indi.woniu.security;

import indi.woniu.mapper.RoleMapper;
import indi.woniu.security.filter.JwtAuthenticationTokenFilter;
import indi.woniu.security.handler.CustomAccessDeniedHandler;
import indi.woniu.utils.JwtUtils;
import lombok.Getter;
import lombok.Setter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.security.servlet.PathRequest;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;

/**
 * @Author: GaN601
 * @Date: 2021/12/7 19:37
 * @Description:
 */
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true, jsr250Enabled = true)
@Getter
@Setter
@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    
    
    /**
     * 登录页面
     */
    @Value("${indi.gan.controller.loginPage}")
    private String loginPage;
    /**
     * 登录接口
     */
    @Value("${indi.gan.controller.login}")
    private String loginInterface;
    /**
     * 访问受限处理器
     */
    @Autowired
    private CustomAccessDeniedHandler customAccessDeniedHandler;
    /**
     * 基础访问权限可访问的
     */
    @Value("${indi.gan.controller.base}")
    private String basePage;
    /**
     * 构建用户信息
     */
    @Autowired
    private UserDetailsService userDetailsService;
    /**
     * 认证成功处理器
     */
    @Autowired
    private AuthenticationSuccessHandler authenticationSuccessHandler;
    /**
     * 认证器, 服务用户登录的认证
     */
    @Autowired
    private AuthenticationProvider authenticationProvider;
    /**
     * 认证失败处理器
     */
    @Autowired
    private AuthenticationFailureHandler authenticationFailureHandler;
    /**
     * 获取角色的信息
     */
    @Autowired
    private RoleMapper roleMapper;
    /**
     * 未认证访问处理器
     */
    @Autowired
    private AuthenticationEntryPoint customAuthenticationEntryPoint;
    @Autowired
    private LogoutSuccessHandler logoutSuccessHandler;
    
    
    /**
     * 配置加密器
     */
    @Bean
    public PasswordEncoder passwordEncoder() {
        return NoOpPasswordEncoder.getInstance();
    }
    
    @Bean
    public JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter() throws Exception {
        return new JwtAuthenticationTokenFilter(authenticationManager());
    }
    
    @Bean
    @ConfigurationProperties("jwt.config")
    public JwtUtils jwtUtils() {
        return new JwtUtils();
    }
    
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        // 数据库存储的用户密码进行加密处理 authenticationProvider 已经使用了这里配置的加密器
        auth.authenticationProvider(authenticationProvider);
    }
    
    @Override
    public void configure(final WebSecurity web) throws Exception {
        // 忽略
        web.ignoring().antMatchers("/user/info").requestMatchers
                (PathRequest.toStaticResources().atCommonLocations());
    }
    
    @Override
    protected void configure(HttpSecurity http) throws Exception {
//        http.authorizeRequests().anyRequest().permitAll().and().cors().and().csrf().disable();
        // 认证授权配置
//        List<Role> roles = roleMapper.selectRoleAllPaths();
        ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry authorize =
                http.authorizeRequests();
/*        // 初始化地址
        for (Role element : roles) {
            if (element.getPaths().get(0) == null) {
                continue;
            }
            authorize.antMatchers(
                    element.getPaths().toArray(new String[0])).hasRole(element.getName());
        }*/
        
        // 登录配置
        authorize
                .and().formLogin().loginProcessingUrl(loginInterface)
                .successHandler(authenticationSuccessHandler)
                .failureHandler(authenticationFailureHandler)
                .permitAll()
        ;
        
        http.logout().logoutUrl("/logout")
                // 登出响应处理器
                .logoutSuccessHandler(logoutSuccessHandler).permitAll().and()
                .userDetailsService(userDetailsService)
                .exceptionHandling()
                // 未认证响应处理器
                .authenticationEntryPoint(customAuthenticationEntryPoint)
                // 未授权响应处理器
                .accessDeniedHandler(customAccessDeniedHandler)
                // 允许跨域
                .and().cors()
                // 禁用 CSRF
                .and().csrf().disable()
        ;
        // 添加过滤器
        http.addFilterBefore(jwtAuthenticationTokenFilter(), UsernamePasswordAuthenticationFilter.class);
    }
    
}
